home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / dskut / exehex.zip / EXEHEX.C next >
C/C++ Source or Header  |  1991-03-30  |  13KB  |  509 lines

  1. /************************************************************************
  2.  * exehex.c -    This program converts Microsoft .EXE files to Intel    *
  3.  *        HEX files suitable for burning into EPROM.  Like the    *
  4.  *        loader in MSDOS, exehex performs any necessary        *
  5.  *        relocation of segments in the .EXE file.        *
  6.  ************************************************************************/
  7.  
  8. /************************************************************************
  9.  * Copyright 1991, Charles F. Harris, C.F. Harris - Consulting.        *
  10.  *                                    *
  11.  * You may use this program for any purpose Commercial or Private with    *
  12.  * following exceptions:                        *
  13.  *                                    *
  14.  * 1) You may not sell this program without my written permission.    *
  15.  * 2) You must leave this header comment unmodified, and intact.    *
  16.  * 3) You must clearly identify any modifications that you make.    *
  17.  *                                    *
  18.  * This program is provided without any warantees or support, and is    *
  19.  * to be used at your own risk.                        *
  20.  ************************************************************************/
  21.  
  22. /************************************************************************
  23.  * This program was designed to run on 80x86 type machines, and to be    *
  24.  * compiled with TURBO C++ V1.00. (that is not to say that it is    *
  25.  * written in C++)                            *
  26.  * I can be reached at: chuck@eng.umd.edu                *
  27.  * or at:    Chuck Harris                        *
  28.  *        C.F. Harris - Consulting                *
  29.  *        9308 Canterbury Riding                    *
  30.  *        Laurel, Maryland 20723                    *
  31.  ************************************************************************/
  32.  
  33. #include <dir.h>
  34. #include <stdio.h>
  35. #include <stdlib.h>
  36. #include <stdarg.h>
  37. #include <string.h>
  38. #include <io.h>
  39.  
  40. #define ERR(s, c)    if(opterr){\
  41.     char errbuf[2];\
  42.     errbuf[0] = c; errbuf[1] = '\n';\
  43.     (void) write(2, argv[0], (unsigned)strlen(argv[0]));\
  44.     (void) write(2, s, (unsigned)strlen(s));\
  45.     (void) write(2, errbuf, 2);}
  46.  
  47. #define DATAREC 0
  48. #define EXADDR    2
  49. #define ENDREC    1
  50.  
  51.  
  52. struct EXEHDR {
  53.     unsigned signature;        /* linker signature */
  54.     unsigned image_rsize;        /* length of image mod 512 */
  55.     unsigned file_nblks;        /* number of 512 byte blocks in file */
  56.     unsigned num_rels;        /* number of relocation items */
  57.     unsigned header_size;        /* size in paragraphs */
  58.     unsigned minheap_size;        /* min num paragraphs in heap */
  59.     unsigned maxheap_size;        /* max num paragraphs in heap */
  60.     unsigned stackseg_offset;    /* offset of stack seg in load module */
  61.     unsigned initial_SP;        /* initial value of stack register */
  62.     unsigned checksum;        /* neg sum of all words in file */
  63.     unsigned initial_IP;        /* initial value of instruction ptr */
  64.     unsigned codeseg_offset;    /* offset of code seg in load module */
  65.     unsigned reltbl_offset;        /* offset of first relocation item */
  66.     unsigned overlay_num;        /* overlay number (0 == resident part) */
  67. } exehdr;
  68.  
  69. typedef struct RELTBL {
  70.     unsigned rel_offset;
  71.     unsigned rel_segment;
  72. } RELTBL;
  73.  
  74. int    opterr = 1;
  75. int    optind = 1;
  76. int    optopt;
  77. char    *optarg;
  78.  
  79. char *tempfile = "exehexXXXXXX";    /* template for mktemp() */
  80. char *tmpfname = 0;            /* name of temp file */
  81.  
  82. FILE *fopen(),*fpi,*fpo,*fpt;
  83. int ABORT(char *reason, ...);
  84.  
  85. unsigned char intelstring[100];
  86. unsigned segment = 0, offset = 0;
  87. unsigned imagelen = 0;
  88. unsigned debug = 0;
  89. unsigned no_end_record = 0;
  90.  
  91. RELTBL *reloc_tbl;
  92.  
  93. main(argc,argv)
  94. int argc;
  95. char **argv;
  96. {
  97.     discover_options(argc,argv);
  98.     open_files(argc,argv);
  99.     read_exe_header();
  100.     read_relocation_table();
  101.     copy_image_to_temp();
  102.     relocate_image();
  103.     write_hex_file();
  104.     remove_temp_file();
  105. }
  106.  
  107. discover_options(argc,argv)
  108. int argc;
  109. char **argv;
  110. {
  111.     char *ourargs = "o:O:s:S:dDN?Hh";
  112.     int opt;
  113.  
  114.     while((opt=getopt(argc,argv,ourargs)) != EOF){
  115.         switch(opt){
  116.         case 'd':
  117.         case 'D':
  118.             fprintf(stderr,"DEBUG level is: %d\n",++debug);
  119.             break;
  120.         case 's':
  121.         case 'S':
  122.             sscanf(optarg,"%x",&segment);
  123.             if(debug>=1){
  124.                 fprintf(stderr,"Segment= 0x%X\n",segment);
  125.             }
  126.             break;
  127.         case 'o':
  128.         case 'O':
  129.             sscanf(optarg,"%x",&offset);
  130.             if(debug>=1){
  131.                 fprintf(stderr,"Offset= 0x%X\n",offset);
  132.             }
  133.             break;
  134.         case 'N':
  135.             no_end_record++;
  136.             if(debug>=1){
  137.                 fprintf(stderr,"No End Record\n");
  138.             }
  139.             break;
  140.         case '?':
  141.         case 'h':
  142.         case 'H':
  143.             how_to_use_message();
  144.             break;
  145.         default:
  146.             ABORT("Unknown argument");
  147.         }
  148.     }
  149. }
  150.  
  151. /*
  152.  * getopt a wonderful little function that handles the command line.
  153.  * available courtesy of AT&T.
  154.  */
  155.  
  156. int
  157. getopt(argc, argv, opts)
  158. int    argc;
  159. char    **argv, *opts;
  160. {
  161.     static int sp = 1;
  162.     register int c;
  163.     register char *cp;
  164.  
  165.     if(sp == 1)
  166.         if(optind >= argc ||
  167.            argv[optind][0] != '-' || argv[optind][1] == '\0')
  168.             return(EOF);
  169.         else if(strcmp(argv[optind], "--") == NULL) {
  170.             optind++;
  171.             return(EOF);
  172.         }
  173.     optopt = c = argv[optind][sp];
  174.     if(c == ':' || (cp=strchr(opts, c)) == NULL) {
  175.         ERR(": illegal option -- ", c);
  176.         if(argv[optind][++sp] == '\0') {
  177.             optind++;
  178.             sp = 1;
  179.         }
  180.         return('?');
  181.     }
  182.     if(*++cp == ':') {
  183.         if(argv[optind][sp+1] != '\0')
  184.             optarg = &argv[optind++][sp+1];
  185.         else if(++optind >= argc) {
  186.             ERR(": option requires an argument -- ", c);
  187.             sp = 1;
  188.             return('?');
  189.         } else
  190.             optarg = argv[optind++];
  191.         sp = 1;
  192.     } else {
  193.         if(argv[optind][++sp] == '\0') {
  194.             sp = 1;
  195.             optind++;
  196.         }
  197.         optarg = NULL;
  198.     }
  199.     return(c);
  200. }
  201.  
  202. open_files(argc,argv)
  203. int argc;
  204. char **argv;
  205. {
  206.     int argind, files_found;
  207.  
  208.     argc--,argv++;            /* skip the program name */
  209.     for(argind=0,files_found=0; argind<argc; argind++){
  210.         if(argv[argind][0] == '-') continue;
  211.         if(debug>=1){
  212.             fprintf(stderr,"Argument is: %s\n",argv[argind]);
  213.         }
  214.         files_found++;
  215.         
  216.         if(files_found==1 && !(fpi=fopen(argv[argind],"rb"))){
  217.             ABORT("opening %s",argv[argind]);
  218.         }
  219.         else if(files_found==2 && !(fpo=fopen(argv[argind],"wb"))){
  220.             ABORT("opening %s",argv[argind]);
  221.         }
  222.         else if(files_found > 2){
  223.             ABORT("too many file arguments\n");
  224.         }
  225.     }
  226.     if(files_found == 0){
  227.         ABORT("need a file to work on!");
  228.     }
  229.     else if(files_found == 1){
  230.         fpo = stdout;
  231.     }
  232.     tmpfname = mktemp(tempfile);
  233.     if(!(fpt=fopen(tmpfname,"wb+"))){
  234.         ABORT("can't open temporary file: %s",tmpfname);
  235.     }
  236. }
  237.  
  238. read_exe_header()
  239. {
  240.     if(fread(&exehdr,sizeof(struct EXEHDR),1,fpi) != 1){
  241.         ABORT("couldn't read exe header");
  242.     }
  243.     if(debug>=1){
  244.         print_exe_header();
  245.     }
  246.     if(exehdr.signature != 0x5a4d){
  247.         ABORT("bad exe signature:[0x%X]",exehdr.signature);
  248.     }
  249.     imagelen  = exehdr.file_nblks*512 - exehdr.header_size*16;
  250.     imagelen -= (exehdr.image_rsize == 4) ? 0 : exehdr.image_rsize;
  251.     if(debug>=1){
  252.         fprintf(stderr,"binary image length is: 0x%X,(%dd)\n",imagelen,imagelen);
  253.     }
  254. }
  255.  
  256. print_exe_header()
  257. {
  258.     fprintf(stderr,"EXE HEADER:\n");
  259.     fprintf(stderr,"->signature       = 0x%X\n",exehdr.signature);
  260.     fprintf(stderr,"->image_rsize     = 0x%X\n",exehdr.image_rsize);
  261.     fprintf(stderr,"->file_nblks      = 0x%X\n",exehdr.file_nblks);
  262.     fprintf(stderr,"->num_rels        = 0x%X\n",exehdr.num_rels);
  263.     fprintf(stderr,"->header_size     = 0x%X\n",exehdr.header_size);
  264.     fprintf(stderr,"->minheap_size    = 0x%X\n",exehdr.minheap_size);
  265.     fprintf(stderr,"->maxheap_size    = 0x%X\n",exehdr.maxheap_size);
  266.     fprintf(stderr,"->stackseg_offset = 0x%X\n",exehdr.stackseg_offset);
  267.     fprintf(stderr,"->initial_SP      = 0x%X\n",exehdr.initial_SP);
  268.     fprintf(stderr,"->checksum        = 0x%X\n",exehdr.checksum);
  269.     fprintf(stderr,"->initial_IP      = 0x%X\n",exehdr.initial_IP);
  270.     fprintf(stderr,"->codeseg_offset  = 0x%X\n",exehdr.codeseg_offset);
  271.     fprintf(stderr,"->reltbl_offset   = 0x%X\n",exehdr.reltbl_offset);
  272.     fprintf(stderr,"->overlay_num     = 0x%X\n",exehdr.overlay_num);
  273. }
  274.  
  275. read_relocation_table()
  276. {
  277.     int i;
  278.  
  279.     if(exehdr.num_rels == 0) return;    /* can't do much here */
  280.  
  281.     reloc_tbl = (RELTBL *)malloc(exehdr.num_rels * sizeof(RELTBL));
  282.     if(!reloc_tbl){
  283.         ABORT("can't malloc reloc_tbl");
  284.     }
  285.     if(fseek(fpi,(long)exehdr.reltbl_offset,SEEK_SET) != 0){
  286.         ABORT("couldn't fseek to relocation tbl");
  287.     }
  288.     if(fread(reloc_tbl, sizeof(RELTBL) * exehdr.num_rels, 1, fpi) != 1){
  289.         ABORT("couldn't read relocation table");
  290.     }
  291.     if(debug>=1){
  292.         fprintf(stderr,"REL